package cn.yudao.ymcc.service.impl;

import cn.yudao.GlobleException;
import cn.yudao.ymcc.domain.Course;
import cn.yudao.ymcc.domain.CourseMarket;
import cn.yudao.ymcc.domain.CourseOrder;
import cn.yudao.ymcc.domain.CourseOrderItem;
import cn.yudao.ymcc.dto.*;
import cn.yudao.ymcc.feign.CourseFeign;
import cn.yudao.ymcc.mapper.CourseOrderMapper;
import cn.yudao.ymcc.result.JSONResult;
import cn.yudao.ymcc.service.ICourseOrderItemService;
import cn.yudao.ymcc.service.ICourseOrderService;
import cn.yudao.ymcc.utils.AssertUtil;
import cn.yudao.ymcc.utils.CodeGenerateUtils;
import cn.yudao.ymcc.utils.SecurityGetUserInfoUtil;
import cn.yudao.ymcc.vo.Course2OrderVo;
import cn.yudao.ymcc.vo.CourseInfoVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale.jia
 * @since 2022-08-18
 */
@Service
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {

    public static final String KEY = "token:%s:%s";

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;


    @Autowired
    private CourseFeign courseFeign;


    @Autowired
    private ICourseOrderItemService courseOrderItemService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public String placeOrder(CourseOrderParamDto dto) {
        // 非空校验--JSR303
        // 检验订单token是否相等--1.获取key
        List<Long> courseIds = dto.getCourseIds();
        String courseId = StringUtils.join(courseIds, ",");
        // 通过自定义的方法获取userInfoParamDto对象得到security上下文对象中的用户信息
        UserInfoParamDto userInfoParamDto = SecurityGetUserInfoUtil.getUserInfoParamDto();
         Long loginId = userInfoParamDto.getId();
        String tokenKey = String.format(KEY, loginId, courseId);
        // 冲redis中获取value--2 获取value
        Object redisValue = redisTemplate.opsForValue().get(tokenKey);
        // 判断是否非空
        AssertUtil.isNotNull(redisValue,"订单异常");
        // 比较token值
        AssertUtil.isTrue(redisValue.toString().equals(dto.getToken()),"订单状态异常");

        // 通过课程id获取课程数据
        JSONResult courseByIds = courseFeign.getCourseByIds(courseIds);
        // 判断是否成功
        AssertUtil.isTrue(courseByIds.isSuccess(),courseByIds.getMessage());
        // 判断是否有课程
        AssertUtil.isNotNull(courseByIds.getData(),"课程不存在");
        // 获取课程和课程销售数据
        CourseInfoVo vo = JSONObject.parseObject(courseByIds.getData().toString(), CourseInfoVo.class);
        List<Course2OrderVo> courseInfos = vo.getCourseInfos();
        // 判断是否有数据
        AssertUtil.isNotNull(courseInfos,"课程不存在");
        // =============================================================
        // 对订单主表数据进行赋值
        CourseOrder courseOrder = new CourseOrder();
        Date now = new Date();
        courseOrder.setCreateTime(now); //创建时间
        String orderSn = CodeGenerateUtils.generateOrderSn(10); //获取订单编号
        courseOrder.setOrderNo(orderSn); //赋值
        courseOrder.setTotalAmount(vo.getTotalAmount()); // 总价
        // courseOrder.setTotalCount(); // 出售商品数量
        courseOrder.setStatusOrder(0);
        courseOrder.setUserId(loginId);
        // courseOrder.setTitle(); // 订单标题
        courseOrder.setPayType(dto.getPayType());
        // insert(courseOrder);
        // ==============================================================
        StringBuilder title = new StringBuilder();
        title.append("购买课程 ");
        // 添加订单得从表
        courseInfos.stream().forEach(courseInfo ->{
            Course course = courseInfo.getCourse();
            // 校验课程状态
            AssertUtil.isTrue(course.getStatus() == Course.STATUS_ON_LINE,"课程未查询到上架");
            CourseMarket courseMarket = courseInfo.getCourseMarket();
            CourseOrderItem courseOrderItem = new CourseOrderItem();
            // courseOrderItem.setOrderId(courseOrder.getId()); //对应秒杀订单
            courseOrderItem.setAmount(courseMarket.getPrice()); //秒杀课程的价格
            courseOrderItem.setCount(1); // 课程数量
            courseOrderItem.setCreateTime(now); // 创建时间
            courseOrderItem.setCourseId(course.getId());
            courseOrderItem.setCourseName(course.getName()); // 课程名字
            courseOrderItem.setCoursePic(course.getPic()); //封面
            courseOrderItem.setOrderNo(courseOrder.getOrderNo()); // 订单编号
            courseOrder.setTotalCount(courseOrder.getTotalCount() + 1); // 给主订单+1
            title.append("[" + course.getName() + ";]");
            // courseOrderItemService.insert(courseOrderItem);
            courseOrder.getItems().add(courseOrderItem); // 主订单添加子订单
        });
        title.append("支付["+ vo.getTotalAmount().toString()  +"] 元");
        courseOrder.setTitle(title.toString()); // 给主订单赋值
        // 发送延迟消息（订单超时处理）--事务消息（本地添加订单-》支付微服务添加支付表）
        sendMqToTranPayAndDelay(dto, courseId, loginId, courseOrder);
        // 删除redis中得token数据
        redisTemplate.delete(tokenKey);

        return courseOrder.getOrderNo();
    }

    private void sendMqToTranPayAndDelay(CourseOrderParamDto dto, String courseId, Long loginId, CourseOrder courseOrder) {
        // 创建发送给支付得对象
        Map<String, String> map = new HashMap<>();
        map.put("userId", loginId.toString());
        map.put("extParams", courseId);
        Order2PayTranMesDto order2PayTranMesDto = new Order2PayTranMesDto(
                courseOrder.getTotalAmount(),
                dto.getPayType(),
                courseOrder.getOrderNo(),
                loginId,
                JSON.toJSONString(map),
                courseOrder.getTitle()
        );
        // 创建发送给支付得对象--message
        Message<Order2PayTranMesDto> message = MessageBuilder.withPayload(order2PayTranMesDto).build();
        // 发送事务消息
        TransactionSendResult txOrderPay = rocketMQTemplate.sendMessageInTransaction(
                "txOrderPay", // 事务组名
                "topic-order:tags-order", // 发送频道
                message, // 消费者消费内容
                courseOrder // 执行本地事务需要得数据
        );
        // 判断是否正确
        LocalTransactionState state = txOrderPay.getLocalTransactionState(); // 执行本地事务状态
        SendStatus status = txOrderPay.getSendStatus(); // 执行本地事务状态
        // 判断本地事务是否执行成功
        if (state != LocalTransactionState.COMMIT_MESSAGE || status != SendStatus.SEND_OK){
            throw new GlobleException("发送异常");
        }
        // updateById(courseOrder); // 修改主订单

        // 发送延迟消息--做订单超时取消
        Message<String> build = MessageBuilder.withPayload(courseOrder.getOrderNo()).build();
        SendResult sendResult = rocketMQTemplate.syncSend(
                "topic-order-level:tags-order-level"
                , build
                , 3000
                , 4);
        SendStatus sendStatus = sendResult.getSendStatus();
        if (sendStatus != SendStatus.SEND_OK){
            throw new GlobleException("发送异常");
        }
    }

    /**
    * @Title: saveOrderAndItem
    * @Description: 新增订单和从订单
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/20 12:30
    * @Parameters:
    * @Return
    */
    @Override
    public boolean saveOrderAndItem(CourseOrder courseOrder) {
        // 判断订单是否已经存在
        AssertUtil.isNull(selectByOrderNo(courseOrder.getOrderNo()),"请勿重复提交订单");
        // 添加主订单
        boolean insert = insert(courseOrder);
        // 添加从订单
        List<CourseOrderItem> items = courseOrder.getItems();
        items.stream().forEach(item -> {
            item.setOrderId(courseOrder.getId());
            courseOrderItemService.insert(item);
        });
        if (insert){
            return true;
        }else {
            return false;
        }
    }

    /**
    * @Title: selectByOrderNo
    * @Description: 根据订单号查询是否有订单
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/20 12:30
    * @Parameters:
    * @Return
    */
    @Override
    public CourseOrder selectByOrderNo(String orderNo) {

        Wrapper<CourseOrder> warpper = new EntityWrapper<>();
        warpper.eq("order_no",orderNo);
        return  selectOne(warpper);
    }

    /**
    * @Title: paySuccessUpOrder
    * @Description: 支付成功之后的回调
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 14:53
    * @Parameters:
    * @Return
    */
    @Override
    @Transactional
    public void paySuccessUpOrder(AliPayNotifyMqDto dto) {
        // 查询数据库订单状态
        CourseOrder courseOrder = selectByOrderNo(dto.getOrderNo());
        if (courseOrder.getStatusOrder() == CourseOrder.STATE_WAIT_PAY){
            // 修改订单状态
            courseOrder.setStatusOrder(CourseOrder.STATE_SUCCESS_PAY);
            courseOrder.setUpdateTime(new Date());
            // 修改
            updateById(courseOrder);
        }else {
            // 发送电话和钉钉到人工--人工处理
        }

    }

    /**
    * @Title: OrderLevel
    * @Description: 订单超时处理
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/21 19:53
    * @Parameters:
    * @Return
    */
    @Override
    @Transactional
    public void OrderLevel(String orderNo) {
        // 获取订单
        CourseOrder courseOrder = selectByOrderNo(orderNo);
        // 判断订单状态--是否为未支付
        if (courseOrder.getStatusOrder() == CourseOrder.STATE_WAIT_PAY){
            courseOrder.setStatusOrder(CourseOrder.STATE_SUCCESS_PAY); // 修改订单状态
            courseOrder.setUpdateTime(new Date());
            updateById(courseOrder);
        }

    }

    /**
    * @Title: killPlaceOrder
    * @Description: 秒杀保存支付单和订单信息
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/24 18:44
    * @Parameters:
    * @Return
    */
    @Override
    public String killPlaceOrder(CourseOrderParamDto dto) {
        // 校验非空 - JSR303
        // 校验当前订单是否存在
        Object tem = redisTemplate.opsForValue().get(dto.getOrderNo());
        AssertUtil.isNotNull(tem,"订单不存在");
        KillOrderDto killOrder = (KillOrderDto) tem;
        // 校验防重复token是否相同
        // 通过自定义的方法获取userInfoParamDto对象得到security上下文对象中的用户信息
        UserInfoParamDto userInfoParamDto = SecurityGetUserInfoUtil.getUserInfoParamDto();
        Long loginId = userInfoParamDto.getId();
        String tokenKey = String.format(KEY, loginId, killOrder.getCourseId());
        Object tokenTmp = redisTemplate.opsForValue().get(tokenKey);
        AssertUtil.isNotNull(tokenTmp,"交易异常");
        boolean equals = tokenTmp.toString().equals(dto.getToken());
        AssertUtil.isTrue(equals,"交易异常");
        // 给订单数据赋值
        CourseOrder courseOrder = new CourseOrder();
        Date now = new Date();
        courseOrder.setCreateTime(now); //创建时间
        courseOrder.setOrderNo(killOrder.getOrderNo()); //赋值
        courseOrder.setTotalAmount(killOrder.getTotalAmount()); // 总价
        courseOrder.setTotalCount(killOrder.getTotalCount()); // 出售商品数量
        courseOrder.setStatusOrder(0);
        courseOrder.setUserId(loginId);
        courseOrder.setTitle("购买课程 [" + killOrder.getCourseName() + ";] , 支付[" + killOrder.getTotalAmount() +"] 元"); // 订单标题
        courseOrder.setPayType(dto.getPayType());
        // 给子订单赋值
        CourseOrderItem courseOrderItem = new CourseOrderItem();
        // courseOrderItem.setOrderId(courseOrder.getId()); //对应秒杀订单
        courseOrderItem.setAmount(killOrder.getTotalAmount()); //秒杀课程的价格
        courseOrderItem.setCount(1); // 课程数量
        courseOrderItem.setCreateTime(now); // 创建时间
        courseOrderItem.setCourseId(killOrder.getCourseId());
        courseOrderItem.setCourseName(killOrder.getCourseName()); // 课程名字
        courseOrderItem.setCoursePic(killOrder.getCoursePic()); //封面
        courseOrderItem.setOrderNo(killOrder.getOrderNo()); // 订单编号
        // 将子订单添加到主订单中
        courseOrder.getItems().add(courseOrderItem);
        // 发送延迟消息（订单超时处理）--事务消息（本地添加订单-》支付微服务添加支付表）
        sendMqToTranPayAndDelay(dto, killOrder.getCourseId().toString(), loginId, courseOrder);
        // 删除redis中的token和预订单信息
        redisTemplate.delete(tokenKey); // 防重复token
        redisTemplate.delete(dto.getOrderNo()); // 预订单
        return dto.getOrderNo();
    }
}
